﻿using System;
using System.Collections.Generic;
using PickGold.Base.OCR.QRCode.Render;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

namespace PickGold.Base.OCR.QRCode
{
	/// <summary>
	/// This class contain two variables. 
	/// BitMatrix for QrCode
	/// isContainMatrix for indicate whether QrCode contains BitMatrix or not.
	/// BitMatrix will equal to null if isContainMatrix is false. 
	/// </summary>
	public class QREncoder
	{
		public ErrorCorrectionLevel ErrorCorrectionLevel
		{
			get;
			set;
		}

		public bool isContainMatrix
		{
			get;
			private set;
		}

		public BitMatrix Matrix
		{
			get;
			private set;
		}

		/// <summary>
		/// Default QrEncoder will set ErrorCorrectionLevel as M
		/// </summary>
		public QREncoder() : this(ErrorCorrectionLevel.M, null) { }

		/// <summary>
		/// QrEncoder with parameter ErrorCorrectionLevel. 
		/// </summary>
		/// <param name="errorCorrectionLevel"></param>
		public QREncoder(ErrorCorrectionLevel errorCorrectionLevel) : this(errorCorrectionLevel, null) { }

		/// <summary>
		/// QrEncoder with parameter ErrorCorrectionLevel. 
		/// </summary>
		/// <param name="errorCorrectionLevel"></param>
		public QREncoder(BitMatrix matrix) : this(ErrorCorrectionLevel.M, matrix) { }

		/// <summary>
		/// QrEncoder with parameter ErrorCorrectionLevel. 
		/// </summary>
		/// <param name="errorCorrectionLevel"></param>
		internal QREncoder(ErrorCorrectionLevel errorCorrectionLevel, BitMatrix matrix)
		{
			this.ErrorCorrectionLevel = errorCorrectionLevel;
			this.isContainMatrix = (matrix != null);
			this.Matrix = matrix;
		}

		//public static void Render(Stream output, string content, ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.M, QuietZoneModules quietZoneModules = QuietZoneModules.Two, int moduleSize = 12)
		//{
		//    var a = FixedModuleSize(moduleSize, quietZones);
		//    using (var g = Graphics.FromImage(new Bitmap(200, 200)))
		//    {
		//        var hdc = g.GetHdc();
		//        using (var mf = new Metafile(output, hdc))
		//        using (var gg = Graphics.FromImage(mf))
		//            this.Draw(gg, matrix);
		//    }
		//}

		/// <summary>
		/// Encode string content to QrCode matrix
		/// </summary>
		/// <exception cref="InputOutOfBoundaryException">
		/// This exception for string content is null, empty or too large</exception>
		public static QREncoder Encode(string content)
		{
			if (string.IsNullOrEmpty(content))
				throw new ArgumentNullException();

			return new QREncoder(QRCodeEncode.Encode(content, ErrorCorrectionLevel.M));
		}

		/// <summary>
		/// Encode string content to QrCode matrix
		/// </summary>
		/// <exception cref="InputOutOfBoundaryException">
		/// This exception for string content is null, empty or too large</exception>
		public static QREncoder Encode(string content, ErrorCorrectionLevel errorCorrectionLevel)
		{
			if (string.IsNullOrEmpty(content))
				throw new ArgumentNullException();

			return new QREncoder(QRCodeEncode.Encode(content, errorCorrectionLevel));
		}

		/// <summary>
		/// Try to encode content
		/// </summary>
		/// <returns>False if input content is empty, null or too large.</returns>
		public static bool TryEncode(string content, out QREncoder qrCode)
		{
			try
			{
				qrCode = QREncoder.Encode(content, ErrorCorrectionLevel.M);
				return true;
			}
			catch (ArgumentNullException)
			{
				qrCode = new QREncoder();
				return false;
			}
		}

		/// <summary>
		/// Try to encode content
		/// </summary>
		/// <returns>False if input content is empty, null or too large.</returns>
		public static bool TryEncode(string content, ErrorCorrectionLevel errorCorrectionLevel, out QREncoder qrCode)
		{
			try
			{
				qrCode = QREncoder.Encode(content, errorCorrectionLevel);
				return true;
			}
			catch (ArgumentNullException)
			{
				qrCode = new QREncoder();
				return false;
			}
		}

		/// <summary>
		/// Encode byte array content to QrCode matrix
		/// </summary>
		/// <exception cref="InputOutOfBoundaryException">
		/// This exception for string content is null, empty or too large</exception>
		public static QREncoder Encode(IEnumerable<byte> content)
		{
			if (content == null)
				throw new ArgumentNullException();

			return new QREncoder(QRCodeEncode.Encode(content, ErrorCorrectionLevel.M));
		}

		/// <summary>
		/// Encode byte array content to QrCode matrix
		/// </summary>
		/// <exception cref="InputOutOfBoundaryException">
		/// This exception for string content is null, empty or too large</exception>
		public static QREncoder Encode(IEnumerable<byte> content, ErrorCorrectionLevel errorCorrectionLevel)
		{
			if (content == null)
				throw new ArgumentNullException();

			return new QREncoder(QRCodeEncode.Encode(content, errorCorrectionLevel));
		}

		/// <summary>
		/// Try to encode content
		/// </summary>
		/// <returns>False if input content is empty, null or too large.</returns>
		public static bool TryEncode(IEnumerable<byte> content, out QREncoder qrCode)
		{
			try
			{
				qrCode = QREncoder.Encode(content, ErrorCorrectionLevel.M);
				return true;
			}
			catch (ArgumentNullException) { }

			qrCode = new QREncoder();
			return false;
		}

		/// <summary>
		/// Try to encode content
		/// </summary>
		/// <returns>False if input content is empty, null or too large.</returns>
		public static bool TryEncode(IEnumerable<byte> content, ErrorCorrectionLevel errorCorrectionLevel, out QREncoder qrCode)
		{
			try
			{
				qrCode = QREncoder.Encode(content, errorCorrectionLevel);
				return true;
			}
			catch (ArgumentNullException) { }

			qrCode = new QREncoder();
			return false;
		}

	}
}
